package cn.lingyangwl.agile.auth.service.impl;

import cn.lingyangwl.agile.auth.constants.CacheKeyEnum;
import cn.lingyangwl.agile.auth.model.rqrs.third.LoginQrcodeGetReq;
import cn.lingyangwl.agile.auth.model.rqrs.third.LoginQrcodeInfo;
import cn.lingyangwl.agile.auth.model.rqrs.third.LoginQrcodeResp;
import cn.lingyangwl.agile.auth.model.rqrs.third.LoginQrcodeTokenResp;
import cn.lingyangwl.agile.auth.oauth2.model.RegisteredClient;
import cn.lingyangwl.agile.auth.service.OAuth2ClientService;
import cn.lingyangwl.agile.auth.service.QrcodeLoginService;
import cn.lingyangwl.agile.auth.third.BaseThirdAuth;
import cn.lingyangwl.agile.model.constants.*;
import cn.lingyangwl.agile.model.module.auth.GrantTypeEnum;
import cn.lingyangwl.agile.model.module.tenant.TenantContext;
import cn.lingyangwl.agile.tenant.core.utils.TenantUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.Objects;

/**
 * @author shenguangyang
 */
@Slf4j
@Service
public class QrcodeLoginServiceImpl implements QrcodeLoginService {
    @Resource
    private OAuth2ClientService clientService;

    @Resource
    private RedisTemplate<String, Object> redisTemplate;

    @Override
    public LoginQrcodeResp getLoginQrcode(LoginQrcodeGetReq req) {
        // 校验客户端是否支持当前身份源登录
        RegisteredClient client = clientService.validOAuthClient(req.getClientId(), null, req.getGrantType(), null, null);
        req.setClient(client);

        try {
            return TenantUtils.execute(DataIsolateLevel.ALL, TenantCons.SYSTEM_TENANT_ID, () -> {
                BaseThirdAuth socialAuth = BaseThirdAuth.getInstance(GrantTypeEnum.of(req.getGrantType()));
                return socialAuth.getLoginQrcode(req);
            });
        } finally {
            TenantContext.clear();
        }
    }

    @Override
    public LoginQrcodeTokenResp getQrcodeToken(String qrcodeId) {
        CacheKeyEnum keyEnum = CacheKeyEnum.LOGIN_QR_CODE;
        String cacheKey = keyEnum.formatKey(qrcodeId);
        LoginQrcodeInfo info = (LoginQrcodeInfo) redisTemplate.opsForValue().get(cacheKey);

        // 返回为空就表示已过期
        if (Objects.isNull(info)) {
            return null;
        }
        if (Boolean.FALSE.equals(info.getIsScan())) {
            LoginQrcodeTokenResp resp = new LoginQrcodeTokenResp();
            resp.setIsScan(false);
            return resp;
        }

        // 校验客户端是否支持当前身份源登录
        RegisteredClient client = clientService.validOAuthClient(info.getClientId(), null, info.getGrantType(), null, null);
        try {
            return TenantUtils.execute(DataIsolateLevel.ALL, TenantCons.SYSTEM_TENANT_ID, () -> {
                BaseThirdAuth socialAuth = BaseThirdAuth.getInstance(GrantTypeEnum.of(info.getGrantType()));
                return socialAuth.getQrcodeToken(client, info);
            });
        } finally {
            TenantContext.clear();
        }
    }

    @Override
    public void userScanQrcode(LoginQrcodeInfo req) {
        CacheKeyEnum keyEnum = CacheKeyEnum.LOGIN_QR_CODE;
        String cacheKey = keyEnum.formatKey(req.getQrcodeId());
        LoginQrcodeInfo info = (LoginQrcodeInfo) redisTemplate.opsForValue().get(cacheKey);
        if (Objects.isNull(info)) {
            log.warn("二维码已过期, 忽略本次用户扫码信息, openId: {}, clientId: {}", req.getOpenId(), req.getClientId());
            return;
        }

        // 更新缓存信息
        info.setIsScan(true).setOpenId(req.getOpenId());
        this.redisTemplate.opsForValue().set(cacheKey, info, keyEnum.getExpire(), keyEnum.getUnit());
    }
}
